package com.hbcx.dto;

import org.openqa.selenium.*;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import javax.management.StandardEmitterMBean;
import java.time.Duration;
import java.util.List;
import java.util.Locale;
import java.util.Set;

public class ElementAction implements Cloneable{
    private String name;
    private String byType;
    private String byValue;
    private int byIndex=-1;
    private String actionType;
    private String actionValue;
    private String frame;
    private String frameByType;
    private int actionPause=0;
    private int afterPause=0;
    private WebElement element;
    private int loop=-1;
    private int loopPause=0;
    private By by = null;
    private ElementAction[] childAction;
    private WindowsAction windowsAction;
    private Group group=null;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getByType() {
        return byType;
    }

    public void setByType(String byType) {
        this.byType = byType;
    }

    public String getByValue() {
        return byValue;
    }

    public void setByValue(String byValue) {
        this.byValue = byValue;
    }

    public String getActionType() {
        return actionType;
    }

    public void setActionType(String actionType) {
        this.actionType = actionType;
    }

    public String getActionValue() {
        return actionValue;
    }

    public void setActionValue(String actionValue) {
        this.actionValue = actionValue;
    }

    public int getActionPause() {
        return actionPause;
    }

    public void setActionPause(int actionPause) {
        this.actionPause = actionPause;
    }

    public WebElement getElement() {
        return element;
    }

    public void setElement(WebElement element) {
        this.element = element;
    }

    public int getAfterPause() {
        return afterPause;
    }

    public void setAfterPause(int afterPause) {
        this.afterPause = afterPause;
    }

    public String getFrame() {
        return frame;
    }

    public void setFrame(String frame) {
        this.frame = frame;
    }

    public int getLoop() {
        return loop;
    }

    public void setLoop(int loop) {
        this.loop = loop;
    }

    public int getLoopPause() {
        return loopPause;
    }

    public void setLoopPause(int loopPause) {
        this.loopPause = loopPause;
    }

    public String getFrameByType() {
        return frameByType;
    }

    public void setFrameByType(String frameByType) {
        this.frameByType = frameByType;
    }

    public ElementAction[] getChildAction() {
        return childAction;
    }

    public void setChildAction(ElementAction[] childAction) {
        this.childAction = childAction;
    }

    public int getByIndex() {
        return byIndex;
    }

    public void setByIndex(int byIndex) {
        this.byIndex = byIndex;
    }

    public WindowsAction getWindowsAction() {
        return windowsAction;
    }

    public void setWindowsAction(WindowsAction windowsAction) {
        this.windowsAction = windowsAction;

    }

    public Group getGroup() {
        return group;
    }

    public void setGroup(Group group) {
        this.group = group;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        ElementAction tmp = (ElementAction) super.clone();
        tmp.setElement(null);
        tmp.setBy(null);
        return tmp;
    }
    public ElementAction cloneAction () {
        try{
            return  (ElementAction)this.clone();
        }catch (CloneNotSupportedException ex)
        {
            throw new RuntimeException("不支持克隆");
        }
    }

    public By getBy() {
        if(by == null){
           this.by = getBy(this.byType,this.byValue);
        }
        return by;
    }

    public void setBy(By by) {
        this.by = by;
    }

    public By getBy(String byType, String value){
        By by;
        byType = byType==null?"":byType.trim().toUpperCase(Locale.ROOT);
        if(byType.isEmpty() || byType.equals("XPATH")){
            by = By.xpath(value);
        }else if(byType.equals("ID")){
            by = By.id(value);
        }else if(byType.equals("CSS")){
            by = By.cssSelector(value);
        }else if(byType.equals("LINKTEXT")){
            by = By.linkText(value);
        }else if(byType.equals("CLASS")){
            by = By.className(value);
        }else {
            by = null;
        }
        return by;
    }

    public void doAction(WebDriver driver) throws InterruptedException {
        fillElement(driver);
        if(loop==-1){
            this.doOnce(driver);
        }else
        {
            while (loop-- > 0){
                this.doOnce(driver);
                if(loop>0)
                {
                    Thread.sleep(this.getLoopPause()*1000L);
                }
            }
        }
    }
    public void doOnce(WebDriver driver) {
        if(this.getByType().trim().toUpperCase(Locale.ROOT).equals("GET"))
        {
            driver.navigate().to(this.getByValue());

            Set<Cookie> cookies= driver.manage().getCookies();
            driver.get(this.getByValue());
            driver.manage().deleteAllCookies();
            cookies.forEach(cookie -> driver.manage().addCookie(cookie));
        }else if(this.getByValue().trim().toUpperCase(Locale.ROOT).equals("POST"))
        {
            //todo: Post
        }else
        {
            String acType = this.actionType.trim().toUpperCase(Locale.ROOT);
            if(acType.equals("SENDKEYS")){
                this.getElement().sendKeys(this.getActionValue());
            }else if(acType.equals("CLICK")){
                WebDriverWait w=new WebDriverWait(driver,20);
                w.until(ExpectedConditions.elementToBeClickable(this.getElement()));
                new Actions(driver)
                        .moveToElement(this.getElement())
                        .pause(Duration.ofSeconds(this.getActionPause()))
                        .click().build().perform();
//                this.getElement().click();
            }else if(acType.equals("DISPLAY"))
            {
                System.out.printf(this.getElement().getText());
            }else if(acType.equals("CHILDACTION"))//child node do actionloop;
            {
                ElementAction ea = this.getChildAction()[0];
                List<WebElement> list =  driver.findElements(ea.getBy());
                for (WebElement webElement : list) {
                    ea.setElement(webElement);
                    ea.doOnce(driver);
                }
            }
        }
    }


    public void fillElement(WebDriver driver)
    {
        if(this.getElement()==null)
        {
            if(this.getByIndex()>=0)
            {
                this.setElement(driver.findElements(this.getBy()).get(this.getByIndex()));
            }else
            {
                this.setElement(driver.findElement(this.getBy()));
            }
        }
    }
}
